//////////////////////////////////////////////////////////////////////////////
//
//  jtag_ctl.v
//
//  Top-level of JTAG controller which includes generic JTAG FSM as well as
//  implementation-specific registers
//
//  JTAG控制器的顶层，包括通用JTAG有限状态机和特定实现的寄存器
//
//  Original Author: 
//  Current Owner:   
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
//////////////////////////////////////////////////////////////////////////////
//
//    Perforce Information
//    $Author: 
//    $File: /rtl/jtag_ctl.v $
//    $DateTime: 
//    $Revision: 
//
//////////////////////////////////////////////////////////////////////////////

`include "np_jtag_macros.v"

`timescale 1ns/10fs
module np_jtag_ctl (
// TAP interface
input  wire         jtag_trst,
//input  wire         jtag_tck,
input  wire         jtag_tms,
input  wire         jtag_tdi,
output wire         jtag_tdo,
output wire         jtag_tdo_en,

// Scan interface
input  wire         scan_mode,
input  wire         scan_set_rst,

// Generic JTAG register control signals
input  wire         jtag_clk,
input  wire         jtag_clk_n,
//output  wire         jtag_clk,
//output  wire         jtag_clk_n,
output wire         jtag_rst,
output wire         jtag_ser_in,
output wire         jtag_capture,
output wire         jtag_shift,
output wire         jtag_update,

// Individual JTAG registers not contained herein
output wire         jtag_cfg_sel,
input  wire         jtag_cfg_tdo
);

wire [`NP_JTAG_DR_IDCODE_LEN-1:0]  idcode;
(*mark_debug = "true"*) wire [`NP_JTAG_IR_WIDTH-1:0]       jtag_ir;
(*mark_debug = "true"*) wire                                 idcode_sel;
wire                                 idcode_tdo;
(*mark_debug = "true"*) wire                                 byp_sel;
wire                                 byp_tdo;
wire                                 byp;

reg                                  jtag_mux_tdo;

//
// // Create a positive and negative jtag clocks to deal with falling-edge flops
// //
// assign jtag_clk = jtag_tck;
// //assign jtag_clk_n = ~jtag_tck;
// gen_clk_mux jtag_clk_n_mux(
//   .out (jtag_clk_n),
//   .sel (scan_mode),
//   .d0  (~jtag_tck),
//   .d1  (jtag_tck)
// );

// JTAG 有限状态机 - 通用JTAG控制器
//
np_jtag_fsm #(.IR_WIDTH(`NP_JTAG_IR_WIDTH),
           .IR_IDCODE(`NP_JTAG_IR_IDCODE))
fsm (
  .trst              (jtag_trst),
  .tck               (jtag_clk),
  .tck_n             (jtag_clk_n),
  .tms               (jtag_tms),
  .tdi               (jtag_tdi),
  .tdo               (jtag_tdo),
  .tdo_en            (jtag_tdo_en),
  .jtag_ir           (jtag_ir),
  .jtag_rst          (jtag_rst),
  .jtag_idle         (),
  .jtag_select       (),
  .jtag_capture      (jtag_capture),
  .jtag_shift        (jtag_shift),
  .jtag_update       (jtag_update),
  .jtag_ser_out      (jtag_mux_tdo),
  .scan_mode_i       (scan_mode),
  .scan_set_rst_i    (scan_set_rst)
);

// 从JTAG TDI串行移位到所有JTAG寄存器
//
assign jtag_ser_in = jtag_tdi;

// 最后的多路复用器，用于将寄存器串行移出至JTAG TDO
//
// 为下面的选择器增加独热
//
always @*
  case (1'b1)
    idcode_sel       : jtag_mux_tdo = idcode_tdo;
    jtag_cfg_sel     : jtag_mux_tdo = jtag_cfg_tdo;
    byp_sel          : jtag_mux_tdo = byp_tdo;
    default          : jtag_mux_tdo = 1'bX;
  endcase

// IDCODE register
//
assign idcode_sel = (jtag_ir == `NP_JTAG_IR_IDCODE);
np_jtag_reg #(.WIDTH(`NP_JTAG_DR_IDCODE_LEN),
           .RST_VAL(0))
idcode_reg (
  .q            (idcode),
  .serial_out   (idcode_tdo),
  .select       (idcode_sel),
  .capture_val  (`NP_JTAG_DR_IDCODE_VAL_ME0),
  .rst          (jtag_rst),
  .clk          (jtag_clk),
  .capture      (jtag_capture),
  .shift        (jtag_shift),
  .serial_in    (jtag_ser_in)
);


assign jtag_cfg_sel = (jtag_ir == `NP_JTAG_IR_CFG);

// BYPASS register - 当没有选择其他寄存器时选择
//
assign byp_sel = (!idcode_sel && !jtag_cfg_sel);

np_jtag_reg #(.WIDTH(1),
           .RST_VAL(1'b0))
byp_reg (
  .q            (byp),
  .serial_out   (byp_tdo),
  .select       (byp_sel),
  .capture_val  (1'b0),
  .rst          (jtag_rst),
  .clk          (jtag_clk),
  .capture      (jtag_capture),
  .shift        (jtag_shift),
  .serial_in    (jtag_ser_in)
);

endmodule
